﻿using System;
using System.Collections.Generic;

using System.Text;

namespace System.Qizx.Xml
{
    /*******************************/
    /// <summary>
    /// Emulates the SAX parsers behaviours.
    /// </summary>
    public class XmlSAXDocumentManager
    {
        protected bool isValidating;
        protected bool namespaceAllowed;
        protected System.Xml.XmlValidatingReader reader;
        protected XmlSaxContentHandler callBackHandler;
        protected XmlSaxErrorHandler errorHandler;
        protected XmlSaxLocatorImpl locator;
        protected XmlSaxLexicalHandler lexical;
        protected XmlSaxEntityResolver entityResolver;
        protected string parserFileName;

        /// <summary>
        /// Public constructor for the class.
        /// </summary>
        public XmlSAXDocumentManager()
        {
            isValidating = false;
            namespaceAllowed = false;
            reader = null;
            callBackHandler = null;
            errorHandler = null;
            locator = null;
            lexical = null;
            entityResolver = null;
            parserFileName = "";
        }

        /// <summary>
        /// Returns a new instance of 'XmlSAXDocumentManager'.
        /// </summary>
        /// <returns>A new 'XmlSAXDocumentManager' instance.</returns>
        public static XmlSAXDocumentManager NewInstance()
        {
            return new XmlSAXDocumentManager();
        }

        /// <summary>
        /// Returns a clone instance of 'XmlSAXDocumentManager'.
        /// </summary>
        /// <returns>A clone 'XmlSAXDocumentManager' instance.</returns>
        public static XmlSAXDocumentManager CloneInstance(XmlSAXDocumentManager instance)
        {
            XmlSAXDocumentManager temp = new XmlSAXDocumentManager();
            temp.NamespaceAllowed = instance.NamespaceAllowed;
            temp.isValidating = instance.isValidating;
            XmlSaxContentHandler contentHandler = instance.getContentHandler();
            if (contentHandler != null)
                temp.setContentHandler(contentHandler);
            XmlSaxErrorHandler errorHandler = instance.getErrorHandler();
            if (errorHandler != null)
                temp.setErrorHandler(errorHandler);
            temp.setFeature("http://xml.org/sax/features/namespaces", instance.getFeature("http://xml.org/sax/features/namespaces"));
            temp.setFeature("http://xml.org/sax/features/namespace-prefixes", instance.getFeature("http://xml.org/sax/features/namespace-prefixes"));
            temp.setFeature("http://xml.org/sax/features/validation", instance.getFeature("http://xml.org/sax/features/validation"));
            temp.setProperty("http://xml.org/sax/properties/lexical-handler", instance.getProperty("http://xml.org/sax/properties/lexical-handler"));
            temp.parserFileName = instance.parserFileName;
            return temp;
        }

        /// <summary>
        /// Indicates whether the 'XmlSAXDocumentManager' are validating the XML over a DTD.
        /// </summary>
        public bool IsValidating
        {
            get
            {
                return isValidating;
            }
            set
            {
                isValidating = value;
            }
        }

        /// <summary>
        /// Indicates whether the 'XmlSAXDocumentManager' manager allows namespaces.
        /// </summary>
        public bool NamespaceAllowed
        {
            get
            {
                return namespaceAllowed;
            }
            set
            {
                namespaceAllowed = value;
            }
        }

        /// <summary>
        /// Emulates the behaviour of a SAX LocatorImpl object.
        /// </summary>
        /// <param name="locator">The 'XmlSaxLocatorImpl' instance to assing the document location.</param>
        /// <param name="textReader">The XML document instance to be used.</param>
        private void UpdateLocatorData(XmlSaxLocatorImpl locator, System.Xml.XmlTextReader textReader)
        {
            if ((locator != null) && (textReader != null))
            {
                locator.setColumnNumber(textReader.LinePosition);
                locator.setLineNumber(textReader.LineNumber);
                locator.setSystemId(parserFileName);
            }
        }

        /// <summary>
        /// Emulates the behavior of a SAX parsers. Set the value of a feature.
        /// </summary>
        /// <param name="name">The feature name, which is a fully-qualified URI.</param>
        /// <param name="value">The requested value for the feature.</param>
        public virtual void setFeature(string name, bool value)
        {
            switch (name)
            {
                case "http://xml.org/sax/features/namespaces":
                    {
                        try
                        {
                            this.NamespaceAllowed = value;
                            break;
                        }
                        catch
                        {
                            throw new ManagerNotSupportedException("The specified operation was not performed");
                        }
                    }
                case "http://xml.org/sax/features/namespace-prefixes":
                    {
                        try
                        {
                            this.NamespaceAllowed = value;
                            break;
                        }
                        catch
                        {
                            throw new ManagerNotSupportedException("The specified operation was not performed");
                        }
                    }
                case "http://xml.org/sax/features/validation":
                    {
                        try
                        {
                            this.isValidating = value;
                            break;
                        }
                        catch
                        {
                            throw new ManagerNotSupportedException("The specified operation was not performed");
                        }
                    }
                default:
                    throw new ManagerNotRecognizedException("The specified feature: " + name + " are not supported");
            }
        }

        /// <summary>
        /// Emulates the behavior of a SAX parsers. Gets the value of a feature.
        /// </summary>
        /// <param name="name">The feature name, which is a fully-qualified URI.</param>
        /// <returns>The requested value for the feature.</returns>
        public virtual bool getFeature(string name)
        {
            switch (name)
            {
                case "http://xml.org/sax/features/namespaces":
                    {
                        try
                        {
                            return this.NamespaceAllowed;
                        }
                        catch
                        {
                            throw new ManagerNotSupportedException("The specified operation was not performed");
                        }
                    }
                case "http://xml.org/sax/features/namespace-prefixes":
                    {
                        try
                        {
                            return this.NamespaceAllowed;
                        }
                        catch
                        {
                            throw new ManagerNotSupportedException("The specified operation was not performed");
                        }
                    }
                case "http://xml.org/sax/features/validation":
                    {
                        try
                        {
                            return this.isValidating;
                        }
                        catch
                        {
                            throw new ManagerNotSupportedException("The specified operation was not performed");
                        }
                    }
                default:
                    throw new ManagerNotRecognizedException("The specified feature: " + name + " are not supported");
            }
        }

        /// <summary>
        /// Emulates the behavior of a SAX parsers. Sets the value of a property.
        /// </summary>
        /// <param name="name">The property name, which is a fully-qualified URI.</param>
        /// <param name="value">The requested value for the property.</param>
        public virtual void setProperty(string name, System.Object value)
        {
            switch (name)
            {
                case "http://xml.org/sax/properties/lexical-handler":
                    {
                        try
                        {
                            lexical = (XmlSaxLexicalHandler)value;
                            break;
                        }
                        catch (System.Exception e)
                        {
                            throw new ManagerNotSupportedException("The property is not supported as an internal exception was thrown when trying to set it: " + e.Message);
                        }
                    }
                default:
                    throw new ManagerNotRecognizedException("The specified feature: " + name + " is not recognized");
            }
        }

        /// <summary>
        /// Emulates the behavior of a SAX parsers. Gets the value of a property.
        /// </summary>
        /// <param name="name">The property name, which is a fully-qualified URI.</param>
        /// <returns>The requested value for the property.</returns>
        public virtual System.Object getProperty(string name)
        {
            switch (name)
            {
                case "http://xml.org/sax/properties/lexical-handler":
                    {
                        try
                        {
                            return this.lexical;
                        }
                        catch
                        {
                            throw new ManagerNotSupportedException("The specified operation was not performed");
                        }
                    }
                default:
                    throw new ManagerNotRecognizedException("The specified feature: " + name + " are not supported");
            }
        }

        /// <summary>
        /// Emulates the behavior of a SAX parser, it realizes the callback events of the parser.
        /// </summary>
        private void DoParsing()
        {
            System.Collections.Hashtable prefixes = new System.Collections.Hashtable();
            System.Collections.Stack stackNameSpace = new System.Collections.Stack();
            locator = new XmlSaxLocatorImpl();
            try
            {
                UpdateLocatorData(this.locator, (System.Xml.XmlTextReader)(this.reader.Reader));
                if (this.callBackHandler != null)
                    this.callBackHandler.setDocumentLocator(locator);
                if (this.callBackHandler != null)
                    this.callBackHandler.startDocument();
                while (this.reader.Read())
                {
                    UpdateLocatorData(this.locator, (System.Xml.XmlTextReader)(this.reader.Reader));
                    switch (this.reader.NodeType)
                    {
                        case System.Xml.XmlNodeType.Element:
                            bool Empty = reader.IsEmptyElement;
                            string namespaceURI = "";
                            string localName = "";
                            if (this.namespaceAllowed)
                            {
                                namespaceURI = reader.NamespaceURI;
                                localName = reader.LocalName;
                            }
                            string name = reader.Name;
                            SaxAttributesSupport attributes = new SaxAttributesSupport();
                            if (reader.HasAttributes)
                            {
                                for (int i = 0; i < reader.AttributeCount; i++)
                                {
                                    reader.MoveToAttribute(i);
                                    string prefixName = (reader.Name.IndexOf(":") > 0) ? reader.Name.Substring(reader.Name.IndexOf(":") + 1, reader.Name.Length - reader.Name.IndexOf(":") - 1) : "";
                                    string prefix = (reader.Name.IndexOf(":") > 0) ? reader.Name.Substring(0, reader.Name.IndexOf(":")) : reader.Name;
                                    bool IsXmlns = prefix.ToLower().Equals("xmlns");
                                    if (this.namespaceAllowed)
                                    {
                                        if (!IsXmlns)
                                            attributes.Add(reader.NamespaceURI, reader.LocalName, reader.Name, "" + reader.NodeType, reader.Value);
                                    }
                                    else
                                        attributes.Add("", "", reader.Name, "" + reader.NodeType, reader.Value);
                                    if (IsXmlns)
                                    {
                                        string namespaceTemp = "";
                                        namespaceTemp = (namespaceURI.Length == 0) ? reader.Value : namespaceURI;
                                        if (this.namespaceAllowed && !prefixes.ContainsKey(namespaceTemp) && namespaceTemp.Length > 0)
                                        {
                                            stackNameSpace.Push(name);
                                            System.Collections.Stack namespaceStack = new System.Collections.Stack();
                                            namespaceStack.Push(prefixName);
                                            prefixes.Add(namespaceTemp, namespaceStack);
                                            if (this.callBackHandler != null)
                                                ((XmlSaxContentHandler)this.callBackHandler).startPrefixMapping(prefixName, namespaceTemp);
                                        }
                                        else
                                        {
                                            if (this.namespaceAllowed && namespaceTemp.Length > 0 && !((System.Collections.Stack)prefixes[namespaceTemp]).Contains(reader.Name))
                                            {
                                                ((System.Collections.Stack)prefixes[namespaceURI]).Push(prefixName);
                                                if (this.callBackHandler != null)
                                                    ((XmlSaxContentHandler)this.callBackHandler).startPrefixMapping(prefixName, reader.Value);
                                            }
                                        }
                                    }
                                }
                            }
                            if (this.callBackHandler != null)
                                this.callBackHandler.startElement(namespaceURI, localName, name, attributes);
                            if (Empty)
                            {
                                if (this.NamespaceAllowed)
                                {
                                    if (this.callBackHandler != null)
                                        this.callBackHandler.endElement(namespaceURI, localName, name);
                                }
                                else
                                    if (this.callBackHandler != null)
                                        this.callBackHandler.endElement("", "", name);
                            }
                            break;

                        case System.Xml.XmlNodeType.EndElement:
                            if (this.namespaceAllowed)
                            {
                                if (this.callBackHandler != null)
                                    this.callBackHandler.endElement(reader.NamespaceURI, reader.LocalName, reader.Name);
                            }
                            else
                                if (this.callBackHandler != null)
                                    this.callBackHandler.endElement("", "", reader.Name);
                            if (this.namespaceAllowed && prefixes.ContainsKey(reader.NamespaceURI) && ((System.Collections.Stack)stackNameSpace).Contains(reader.Name))
                            {
                                stackNameSpace.Pop();
                                System.Collections.Stack namespaceStack = (System.Collections.Stack)prefixes[reader.NamespaceURI];
                                while (namespaceStack.Count > 0)
                                {
                                    string tempString = (System.String)namespaceStack.Pop();
                                    if (this.callBackHandler != null)
                                        ((XmlSaxContentHandler)this.callBackHandler).endPrefixMapping(tempString);
                                }
                                prefixes.Remove(reader.NamespaceURI);
                            }
                            break;

                        case System.Xml.XmlNodeType.Text:
                            if (this.callBackHandler != null)
                                this.callBackHandler.characters(reader.Value.ToCharArray(), 0, reader.Value.Length);
                            break;

                        case System.Xml.XmlNodeType.Whitespace:
                            if (this.callBackHandler != null)
                                this.callBackHandler.ignorableWhitespace(reader.Value.ToCharArray(), 0, reader.Value.Length);
                            break;

                        case System.Xml.XmlNodeType.ProcessingInstruction:
                            if (this.callBackHandler != null)
                                this.callBackHandler.processingInstruction(reader.Name, reader.Value);
                            break;

                        case System.Xml.XmlNodeType.Comment:
                            if (this.lexical != null)
                                this.lexical.comment(reader.Value.ToCharArray(), 0, reader.Value.Length);
                            break;

                        case System.Xml.XmlNodeType.CDATA:
                            if (this.lexical != null)
                            {
                                lexical.startCDATA();
                                if (this.callBackHandler != null)
                                    this.callBackHandler.characters(this.reader.Value.ToCharArray(), 0, this.reader.Value.ToCharArray().Length);
                                lexical.endCDATA();
                            }
                            break;

                        case System.Xml.XmlNodeType.DocumentType:
                            if (this.lexical != null)
                            {
                                string lname = this.reader.Name;
                                string systemId = null;
                                if (this.reader.Reader.AttributeCount > 0)
                                    systemId = this.reader.Reader.GetAttribute(0);
                                this.lexical.startDTD(lname, null, systemId);
                                this.lexical.startEntity("[dtd]");
                                this.lexical.endEntity("[dtd]");
                                this.lexical.endDTD();
                            }
                            break;
                    }
                }
                if (this.callBackHandler != null)
                    this.callBackHandler.endDocument();
            }
            catch (System.Xml.XmlException e)
            {
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified file and process the events over the specified handler.
        /// </summary>
        /// <param name="filepath">The file to be used.</param>
        /// <param name="handler">The handler that manages the parser events.</param>
        public virtual void parse(System.IO.FileInfo filepath, XmlSaxContentHandler handler)
        {
            try
            {
                if (handler is XmlSaxDefaultHandler)
                {
                    this.errorHandler = (XmlSaxDefaultHandler)handler;
                    this.entityResolver = (XmlSaxDefaultHandler)handler;
                }
                if (!(this is XmlSaxParserAdapter))
                    this.callBackHandler = handler;
                else
                {
                    if (this.callBackHandler == null)
                        this.callBackHandler = handler;
                }
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(filepath.OpenRead());
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = filepath.FullName;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified file path and process the events over the specified handler.
        /// </summary>
        /// <param name="filepath">The path of the file to be used.</param>
        /// <param name="handler">The handler that manage the parser events.</param>
        public virtual void parse(string filepath, XmlSaxContentHandler handler)
        {
            try
            {
                if (handler is XmlSaxDefaultHandler)
                {
                    this.errorHandler = (XmlSaxDefaultHandler)handler;
                    this.entityResolver = (XmlSaxDefaultHandler)handler;
                }
                if (!(this is XmlSaxParserAdapter))
                    this.callBackHandler = handler;
                else
                {
                    if (this.callBackHandler == null)
                        this.callBackHandler = handler;
                }
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(filepath);
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = filepath;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified stream and process the events over the specified handler.
        /// </summary>
        /// <param name="stream">The stream with the XML.</param>
        /// <param name="handler">The handler that manage the parser events.</param>
        public virtual void parse(System.IO.Stream stream, XmlSaxContentHandler handler)
        {
            try
            {
                if (handler is XmlSaxDefaultHandler)
                {
                    this.errorHandler = (XmlSaxDefaultHandler)handler;
                    this.entityResolver = (XmlSaxDefaultHandler)handler;
                }
                if (!(this is XmlSaxParserAdapter))
                    this.callBackHandler = handler;
                else
                {
                    if (this.callBackHandler == null)
                        this.callBackHandler = handler;
                }
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(stream);
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = null;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified stream and process the events over the specified handler, and resolves the 
        /// entities with the specified URI.
        /// </summary>
        /// <param name="stream">The stream with the XML.</param>
        /// <param name="handler">The handler that manage the parser events.</param>
        /// <param name="URI">The namespace URI for resolve external etities.</param>
        public virtual void parse(System.IO.Stream stream, XmlSaxContentHandler handler, string URI)
        {
            try
            {
                if (handler is XmlSaxDefaultHandler)
                {
                    this.errorHandler = (XmlSaxDefaultHandler)handler;
                    this.entityResolver = (XmlSaxDefaultHandler)handler;
                }
                if (!(this is XmlSaxParserAdapter))
                    this.callBackHandler = handler;
                else
                {
                    if (this.callBackHandler == null)
                        this.callBackHandler = handler;
                }
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(URI, stream);
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = null;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified 'XmlSource' instance and process the events over the specified handler, 
        /// and resolves the entities with the specified URI.
        /// </summary>
        /// <param name="source">The 'XmlSource' that contains the XML.</param>
        /// <param name="handler">The handler that manages the parser events.</param>
        public virtual void parse(XmlSource source, XmlSaxContentHandler handler)
        {
            if (source.Characters != null)
                parse(source.Characters.BaseStream, handler);
            else
            {
                if (source.Bytes != null)
                    parse(source.Bytes, handler);
                else
                {
                    if (source.Uri != null)
                        parse(source.Uri, handler);
                    else
                        throw new System.Xml.XmlException("The XmlSource class can't be null");
                }
            }
        }

        /// <summary>
        /// Parses the specified file and process the events over previously specified handler.
        /// </summary>
        /// <param name="filepath">The file with the XML.</param>
        public virtual void parse(System.IO.FileInfo filepath)
        {
            try
            {
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(filepath.OpenRead());
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = filepath.FullName;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified file path and processes the events over previously specified handler.
        /// </summary>
        /// <param name="filepath">The path of the file with the XML.</param>
        public virtual void parse(string filepath)
        {
            try
            {
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(filepath);
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = filepath;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified stream and process the events over previusly specified handler.
        /// </summary>
        /// <param name="stream">The stream with the XML.</param>
        public virtual void parse(System.IO.Stream stream)
        {
            try
            {
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(stream);
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = null;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified stream and processes the events over previously specified handler, and resolves the 
        /// external entities with the specified URI.
        /// </summary>
        /// <param name="stream">The stream with the XML.</param>
        /// <param name="URI">The namespace URI for resolve external etities.</param>
        public virtual void parse(System.IO.Stream stream, string URI)
        {
            try
            {
                System.Xml.XmlTextReader tempTextReader = new System.Xml.XmlTextReader(URI, stream);
                System.Xml.XmlValidatingReader tempValidatingReader = new System.Xml.XmlValidatingReader(tempTextReader);
                parserFileName = null;
                tempValidatingReader.ValidationType = (this.isValidating) ? System.Xml.ValidationType.DTD : System.Xml.ValidationType.None;
                tempValidatingReader.ValidationEventHandler += new System.Xml.Schema.ValidationEventHandler(this.ValidationEventHandle);
                this.reader = tempValidatingReader;
                this.DoParsing();
            }
            catch (System.Xml.XmlException e)
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(e);
                throw e;
            }
        }

        /// <summary>
        /// Parses the specified 'XmlSource' and processes the events over the specified handler, and 
        /// resolves the entities with the specified URI.
        /// </summary>
        /// <param name="source">The 'XmlSource' instance with the XML.</param>
        public virtual void parse(XmlSource source)
        {
            if (source.Characters != null)
                parse(source.Characters.BaseStream);
            else
            {
                if (source.Bytes != null)
                    parse(source.Bytes);
                else
                {
                    if (source.Uri != null)
                        parse(source.Uri);
                    else
                        throw new System.Xml.XmlException("The XmlSource class can't be null");
                }
            }
        }

        /// <summary>
        /// Manages all the exceptions that were thrown when the validation over XML fails.
        /// </summary>
        public void ValidationEventHandle(System.Object sender, System.Xml.Schema.ValidationEventArgs args)
        {
            System.Xml.Schema.XmlSchemaException tempException = args.Exception;
            if (args.Severity == System.Xml.Schema.XmlSeverityType.Warning)
            {
                if (this.errorHandler != null)
                    this.errorHandler.warning(new System.Xml.XmlException(tempException.Message, tempException, tempException.LineNumber, tempException.LinePosition));
            }
            else
            {
                if (this.errorHandler != null)
                    this.errorHandler.fatalError(new System.Xml.XmlException(tempException.Message, tempException, tempException.LineNumber, tempException.LinePosition));
            }
        }

        /// <summary>
        /// Assigns the object that will handle all the content events.
        /// </summary>
        /// <param name="handler">The object that handles the content events.</param>
        public virtual void setContentHandler(XmlSaxContentHandler handler)
        {
            if (handler != null)
                this.callBackHandler = handler;
            else
                throw new System.Xml.XmlException("Error assigning the Content handler: a null Content Handler was received");
        }

        /// <summary>
        /// Assigns the object that will handle all the error events. 
        /// </summary>
        /// <param name="handler">The object that handles the errors events.</param>
        public virtual void setErrorHandler(XmlSaxErrorHandler handler)
        {
            if (handler != null)
                this.errorHandler = handler;
            else
                throw new System.Xml.XmlException("Error assigning the Error handler: a null Error Handler was received");
        }

        /// <summary>
        /// Obtains the object that will handle all the content events.
        /// </summary>
        /// <returns>The object that handles the content events.</returns>
        public virtual XmlSaxContentHandler getContentHandler()
        {
            return this.callBackHandler;
        }

        /// <summary>
        /// Assigns the object that will handle all the error events. 
        /// </summary>
        /// <returns>The object that handles the error events.</returns>
        public virtual XmlSaxErrorHandler getErrorHandler()
        {
            return this.errorHandler;
        }

        /// <summary>
        /// Returns the current entity resolver.
        /// </summary>
        /// <returns>The current entity resolver, or null if none has been registered.</returns>
        public virtual XmlSaxEntityResolver getEntityResolver()
        {
            return this.entityResolver;
        }

        /// <summary>
        /// Allows an application to register an entity resolver.
        /// </summary>
        /// <param name="resolver">The entity resolver.</param>
        public virtual void setEntityResolver(XmlSaxEntityResolver resolver)
        {
            this.entityResolver = resolver;
        }
    }
}
